package core.physics;

import java.awt.Point;

import physicsNatures.AbstractPhysicsNature;
import util.math.Angle;

/**
 * Singleton class for handling physics calculations such as collisions. An
 * instance of PhysicsCalculator must be called to use it.
 * 
 * @author Nathan Klug
 * 
 */
public class PhysicsCalculator {

    static PhysicsCalculator myInstance;
    private static boolean isOn;

    private PhysicsCalculator() {
        isOn = true;
    }

    /**
     * Returns an instance of Physics Calculator.
     * 
     * @return
     */
    public static PhysicsCalculator getInstance() {
        if (myInstance == null) {
            myInstance = new PhysicsCalculator();
        }
        return myInstance;
    }

    /**
     * Elastic collision method. Coefficient of Restitution is set to 1.
     * 
     * @param object1
     * @param object2
     * @param pointOfCollision
     * @param angleOfImpact
     */
    public void elasticCollision(AbstractPhysicsNature object1, AbstractPhysicsNature object2, Angle angleOfImpact, Point pointOfImpact) {
        collision(object1, object2, angleOfImpact, pointOfImpact, 1);
    }

    /**
     * Inelastic collision method. Coefficient of Restitution is set to 0.
     * 
     * @param object1
     * @param object2
     * @param pointOfCollision
     * @param angleOfImpact
     */
    public void inelasticCollision(AbstractPhysicsNature object1, AbstractPhysicsNature object2, Angle angleOfImpact, Point pointOfImpact) {
        collision(object1, object2, angleOfImpact, pointOfImpact, 0);
    }

    /**
     * General collision method. Tells the two physical objects that a collision
     * occurred.
     * 
     * @param object1
     * @param object2
     * @param pointOfCollision
     * @param angleOfImpact
     * @param coefficientOfRestitution
     */
    public void collision(AbstractPhysicsNature object1, AbstractPhysicsNature object2, Angle angleOfImpact, Point pointOfImpact, double coefficientOfRestitution) {
        if (isOn) {
            object1.collisionOccurred(object2, angleOfImpact, pointOfImpact, coefficientOfRestitution);
            object2.collisionOccurred(object1, angleOfImpact, pointOfImpact, coefficientOfRestitution);
        }
    }
    
    /**
     * If no coefficient of restitution is given, default is elastic collision.
     * @param object1
     * @param object2
     * @param angleOfImpact
     * @param pointOfImpact
     */
    public void collision(AbstractPhysicsNature object1, AbstractPhysicsNature object2, Angle angleOfImpact, Point pointOfImpact) {
	elasticCollision(object1, object2, angleOfImpact, pointOfImpact);
    }

    /**
     * Returns a boolean value representing if physics is on
     * 
     * @return
     */
    public boolean isOn() {
        return isOn;
    }

    /**
     * Turns physics off
     */
    public void turnOff() {
        isOn = false;
    }

    /**
     * Turns physics on
     */
    public void turnOn() {
        isOn = true;
    }

    /**
     * Sets the physics on/off based on the input boolean
     * 
     * @param newState
     */
    public void setPhysicsOnOff(boolean newState) {
        isOn = newState;
    }

    /**
     * Turns physics on if it is off and turns physics off if it is on
     */
    public void togglePhysicsOnOff() {
        isOn = !isOn;
    }
}
